package com.miplus.ccrm.uploadjob.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.miplus.ccrm.common.JPubUtils;
import com.miplus.ccrm.common.JTimer;
import com.miplus.ccrm.uploadjob.mapper.AsrCallhistMapper;
import com.miplus.ccrm.uploadjob.mapper.TRecorderMapper;
import com.miplus.ccrm.uploadjob.pojo.AsrCallhist;
import com.miplus.ccrm.uploadjob.pojo.TRecorder;
import com.miplus.ccrm.uploadjob.service.qm.QmDataService;
import com.miplus.ccrm.uploadjob.service.xsky.XSkyService;
import com.miplus.ccrm.uploadjob.service.aliyun.AliyunService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.util.FileUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.io.IOException;
import java.nio.file.*;

@Slf4j
@Service
public class JCheckTimer extends JTimer {
    @Value("${cti.recordfileDir}")
    private String cti_recfileDir;
    @Value("${aliyun.recordfileDir}")
    private String aly_recfileDir;
    @Value("${cti.uploadcheckday}")
    private Integer cti_uploadcheckday;
    @Value("${cti.uploadcheckspan}")
    private Integer cti_uploadcheckspan;
    @Value("${cti.uploadokremove}")
    private String cti_uploadokremove;
    @Value("${cti.recorderip}")
    private String cti_recorderip;
    @Value("${cti.recfilebakdir}")
    private String cti_recfilebakdir;
    @Value("${ccrm.recfile.savemode:}")
    private String recfile_savemode;
    @Value("${ai.asr.url:}")
    private String asr_url;
    @Value("${ai.asr.userid:}")
    private String asr_userid;
    @Value("${ai.asr.token:}")
    private String asr_token;
    @Value("${ai.asr.mp3:}")
    private String asr_mp3;
    @Resource
    private TRecorderMapper tRecorderMapper;
    @Resource
    private XSkyService ossServiceFile;
    @Resource
    private AliyunService aliyunService;
    private String todayFilebakDir = "";
    @Resource
    private AsrCallhistMapper asrCallhistMapper;
    @Resource
    private QmDataService qmDataService;

    public JCheckTimer() {
    }

    public int InitTimer() {
        log.info("InitTimer:uploadcheckspan={}", cti_uploadcheckspan);

        return this.StartTimer("timer", cti_uploadcheckspan);
    }

    @Override
    public boolean OnTimer() {
        try {
            if (JPubUtils.IsEmpty(cti_recorderip)) {
                cti_recorderip = JPubUtils.getLocalIPAddr();
            }
            if (JPubUtils.IsEqual(recfile_savemode, "xsky")) {
                CheckUploadBakDir();
                OnUploadRecord();
            }
            if (JPubUtils.IsNotEmpty(aly_recfileDir)) {
                OnRecordAsrResult();
                OnRecordAsrParse();
            }

            log.info("OnTimer.Done:{}", this.isRunning);
        } catch (Exception e) {
            log.warn("OnTimer.Err:{}", e.getMessage());
        }

        return true;
    }

    private void CheckUploadBakDir() {//2024-10-09
        todayFilebakDir = "";
        if (JPubUtils.IsEmpty(cti_recfilebakdir)) {
            log.info("CheckUploadBakDir.NoSet:cti.recfilebakdir");
            return;
        }
        log.info("CheckUploadBakDir:{}", cti_recfilebakdir);
        try {
            File file = new File(cti_recfilebakdir);
            if (!file.exists()) {
                log.info("CheckUploadBakDir:Create Dir={}", cti_recfilebakdir);
                file.mkdirs();
            }
            todayFilebakDir = cti_recfilebakdir;
            if (!todayFilebakDir.endsWith("/")) {
                todayFilebakDir += "/";
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            todayFilebakDir += sdf.format(new Date());
            file = new File(todayFilebakDir);
            if (!file.exists()) {
                log.info("CheckUploadBakDir:Create today={}", todayFilebakDir);
                file.mkdirs();
            }
        } catch (Exception e) {
            todayFilebakDir = "";
            log.error("CheckUploadBakDir:{}", e.getMessage());
        }
    }

    private void OnUploadRecord() {
        int iday = 0 - cti_uploadcheckday;
        Date gedt = JPubUtils.addDays(new Date(), iday);
        log.info("OnUploadRecord:recorderip={},iday={},gedt={}",
                cti_recorderip, iday, JPubUtils.DTimeToString(gedt)
        );
        List<TRecorder> recorderList = tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .ge("starttime", gedt)
                        .eq("available", "1")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip), "recorderip", cti_recorderip)
                        .exists("select 1 from report_call_hist h where h.CALLMANAGENUMBER=t.CALLID and h.ENDDATETIME is not null")
                        .apply("(taskflag is null or taskflag in ('0','-1','-2'))")
                        .le("rownum", 200)
        );
        if (JPubUtils.IsEmpty(recorderList)) {
            log.info("OnUploadRecord.IsNull");
            return;
        }
        for (TRecorder rec : recorderList) {
            String recid = rec.getRecorderid();
            try {
                String filename = rec.getFilename();
                String filepath = "";
                if (JPubUtils.IsEqual(rec.getAgentid(), "qm") ||
                        JPubUtils.IsEqual(rec.getAgentid(), "ivr")) {
                    filepath = rec.getFilepath() + filename;
                } else {
                    filepath = getRecFilePathName(filename, rec.getFilepath());
                }
                File file = new File(filepath);
                TRecorder tRecorder = new TRecorder();
                tRecorder.setRecorderid(recid);
                tRecorder.setUploaddt(new Date());
                tRecorder.setInfotype("XSKY");
                boolean uploadok = false;
                log.info("OnUploadRecord({}):file={},size={}", recid, filepath, file.length());
                if (file.exists()) {
                    if (ossServiceFile.UploadFile(filename, file)) {
                        tRecorder.setInfoid(filename);
                        tRecorder.setInfodepart(String.format("SUCCESS:%d", file.length()));
                        uploadok = true;
                    } else {
                        Integer failcnt = JPubUtils.StringToInt(rec.getInfoid());
                        failcnt = failcnt - 1;
                        tRecorder.setInfoid(failcnt.toString());
                        tRecorder.setInfodepart("FAIL");
                    }
                } else {
                    tRecorder.setInfoid("-99");
                    tRecorder.setInfodepart("File.NoExist");
                }
                log.info("OnUploadRecord({}):Result={}", recid, tRecorder.getInfodepart());

                tRecorderMapper.updateById(tRecorder);

                if (uploadok) {
                    if (JPubUtils.IsEqual(cti_uploadokremove, "1")) {
                        DeleteFile(file, filename);
                    } else if (JPubUtils.IsNotEmpty(todayFilebakDir)) {
                        RemoveFile(file, filename, todayFilebakDir);
                    }
                }
            } catch (Exception e) {
                log.warn("OnUploadRecord({}).Err:{}", recid, e.getMessage());
                e.printStackTrace();
            }
        }
    }

    private void DeleteFile(File file, String filename) {
        log.info("DeleteFile:{}", filename);
        try {
            file.delete();
        } catch (Exception e) {
            log.warn("DeleteFile.Err:{}", e.getMessage());
        }
    }

    private void RemoveFile(File file, String filename, String tofiledir) {
        log.info("RemoveFile:{} To {}", filename, tofiledir);
        try {
            File tofile = new File(tofiledir + "/" + filename);
            FileUtil.copyFile(file, tofile);

            DeleteFile(file, filename);
        } catch (Exception e) {
            log.warn("RemoveFile.Err:{}", e.getMessage());
        }
    }

    private String getRecFilePathName(String filename, String path) {
        String fpath = cti_recfileDir + path;
        if (!fpath.endsWith("/")) {
            fpath = fpath + "/";
        }
        return fpath + filename;
    }

    private void OnRecordAsrParse() {
        int iday = 0 - cti_uploadcheckday;
        Date gedt = JPubUtils.addDays(new Date(), iday);
        log.info("OnRecordAsrParse:aly_recfileDir={},recorderip={},iday={},gedt={}",
                aly_recfileDir, cti_recorderip, iday, JPubUtils.DTimeToString(gedt)
        );
        List<TRecorder> recorderList = tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .selectAll(TRecorder.class)
                        .ge(TRecorder::getStarttime, gedt)
                        .eq(TRecorder::getAvailable, "1")
                        .notIn(TRecorder::getAgentid, "ivr","robotai")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip), "recorderip", cti_recorderip)
                        .exists("select 1 from report_call_hist h where h.CALLMANAGENUMBER=t.CALLID and h.ENDDATETIME is not null")
                        .apply("(taskflag is null or taskflag in ('0','-1','-2'))")
                        .le("rownum", 200)
        );
        if (JPubUtils.IsEmpty(recorderList)) {
            //下面是导入的文件数据
            recorderList = tRecorderMapper.selectList(
                    new MPJLambdaWrapper<TRecorder>()
                            .selectAll(TRecorder.class)
                            .ge(TRecorder::getStarttime, gedt)
                            .eq(TRecorder::getAvailable, "1")
                            .eq(TRecorder::getAgentid, "qm")
                            .apply("(taskflag is null or taskflag in ('0','-1','-2'))")
                            .le("rownum", 200)
            );
        }
        if (JPubUtils.IsEmpty(recorderList)) {
            log.info("OnRecordAsrParse.IsNull");
            return;
        }

        //上传文件至公网代理文件夹
        fileUpload(recorderList);

        for (TRecorder rec : recorderList) {
            String recid = rec.getRecorderid();
            String filepath = "";
            String filename = rec.getFilename();
            if (JPubUtils.IsEqual(rec.getAgentid(), "qm") ||
                    JPubUtils.IsEqual(rec.getAgentid(), "ivr")) {
                filepath = rec.getFilepath() + filename;
            } else {
                //filepath = getRecFilePathName(filename, rec.getFilepath());
                filepath = aly_recfileDir + filename;
            }
            log.info("OnRecordAsrParse.filepath={}", filepath);
            //File file = new File(filepath);
            TRecorder tRecorder = new TRecorder();
            tRecorder.setRecorderid(recid);
            tRecorder.setUpasrdt(new Date());
            if (JPubUtils.IsEmpty(filepath)) {
                log.warn("OnRecordAsrParse:{} NoFind", filepath);
                tRecorder.setTaskmark("File.NoExist");
                tRecorder.setTaskflag("-99");
            } else {
                log.info("OnRecordAsrParse({}):file={}", recid, filepath);
                String taskId = aliyunService.submitFileTransRequest(filepath);
                if (JPubUtils.IsEmpty(taskId)) {
                    log.info("OnRecordAsrParse({}):filepath={}:taskId:{}", recid, filepath, taskId);
                    Integer failcnt = JPubUtils.StringToInt(rec.getTaskflag());
                    failcnt = failcnt - 1;
                    tRecorder.setTaskflag(failcnt.toString());
                } else {
                    tRecorder.setTaskmark(taskId);
                    tRecorder.setTaskflag("1");
                }
            }
//            if(file.exists()){
//                log.info("OnRecordAsrParse({}):file={}", recid,filepath);
//                String urlasrfile=DoAsrRequest(file);
//                log.info("OnRecordAsrParse({}):Result:{}", recid,urlasrfile);
//                if(JPubUtils.IsEmpty(urlasrfile)){//fail
//                    Integer failcnt=JPubUtils.StringToInt(rec.getTaskflag());
//                    failcnt=failcnt-1;
//                    tRecorder.setTaskflag(failcnt.toString());
//                }
//                else {//success
//                    tRecorder.setTaskmark(urlasrfile);
//                    tRecorder.setTaskflag("1");
//                }
//            }
//            else{
//                log.warn("OnRecordAsrParse:{} NoFind", filepath);
//                tRecorder.setTaskmark("File.NoExist");
//                tRecorder.setTaskflag("-99");
//            }
            tRecorderMapper.updateById(tRecorder);
        }
    }

    private void fileUpload(List<TRecorder> recorderList) {
        String filepath = "/data/recordingdata/";
        for (TRecorder rec : recorderList) {
            // 源文件路径
            Path sourcePath = Paths.get(filepath + rec.getFilepath() + rec.getFilename());
            // 目标目录路径
            Path targetDir = Paths.get("/data/uploadrec");
            try {
                // 如果目标目录不存在，则创建
                if (!Files.exists(targetDir)) {
                    Files.createDirectories(targetDir);
                }

                // 构建目标文件路径
                Path targetPath = targetDir.resolve(sourcePath.getFileName());

                // 复制文件（如果希望移动文件，使用 Files.move()）
                Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);

                log.info("fileUpload.文件上传成功!");
            } catch (IOException e) {
                log.error("fileUpload.Err:{}", e.getMessage());
            }
        }
    }

    private String DoAsrRequest(File uploadfile) {
        String urlasrfile = "";
        String urlbody = asr_url + "dotcmultispksplit3?lanid=0";
        //String wavfile="E:/Sound/1101.wav";
        log.info("DoAsrRequest:{}", urlbody);
        try {
            HttpResponse<JsonNode> response = Unirest.post(urlbody)
                    .field("userid", asr_userid)
                    .field("token", asr_token)
                    .field("asr", "1")
                    .field("mp", "0")
                    .field("file", uploadfile)
                    .field("mp3", asr_mp3)
                    .asJson();
            log.info("DoAsrRequest.Response:{}", response.getBody());
            int status = response.getStatus();
            if (status == 200) {
                JsonNode responseBody = response.getBody();
                String code = responseBody.getObject().getString("errCode");
                if (JPubUtils.IsEqual(code, "0")) {
                    urlasrfile = responseBody.getObject().getString("result");
                } else {
                    log.warn("DoAsrRequest.Fail:code={}", code);
                }
            } else {
                log.warn("DoAsrRequest.Fail:status={}", status);
            }
        } catch (Exception e) {
            log.error("DoAsrRequest.Err:{}", e.getMessage());
        }

        return urlasrfile;
    }

    private void OnRecordAsrResult() {
        int iday = 0 - cti_uploadcheckday;
        Date gedt = JPubUtils.addDays(new Date(), iday);
        log.info("OnRecordAsrResult:recorderip={},iday={},gedt={}",
                cti_recorderip, iday, JPubUtils.DTimeToString(gedt)
        );
        List<TRecorder> recorderList = tRecorderMapper.selectList(
                new MPJLambdaWrapper<TRecorder>()
                        .ge(TRecorder::getStarttime, gedt)
                        .ne(TRecorder::getAgentid, "ivr")
                        .eq(JPubUtils.IsNotEmpty(cti_recorderip), "recorderip", cti_recorderip)
                        .eq(TRecorder::getTaskflag, "1")
        );
        if (JPubUtils.IsEmpty(recorderList)) {
            log.info("OnRecordAsrResult.IsNull");
            return;
        }

        for (TRecorder rec : recorderList) {
            String taskId = rec.getTaskmark();
            if (JPubUtils.IsEmpty(taskId)) {//理论上不存在
                log.warn("OnRecordAsrResult.TaskId Null");
            } else {
                DoParseAsrResult(taskId, rec);
            }
        }
    }

    public String GetNextUID(String iden, Integer index) {
        String s = String.valueOf((new Date()).getTime());
        s += index.toString();
        if (iden != null) s += "." + iden;
        return s;
    }

    private void DoParseAsrResult(String taskId, TRecorder rec) {
        try {
            String asrResult = aliyunService.getFileTransResult(taskId);
            if (JPubUtils.IsEmpty(asrResult)) {
                log.warn("DoParseAsrResult.asrResult Null");
            } else {
                JSONObject r = JSONObject.parseObject(asrResult);
                JSONArray sentencesArray = r.getJSONArray("Sentences");
                for (int i = 0; i < sentencesArray.size(); i++) {
                    JSONObject sentence = sentencesArray.getJSONObject(i);
                    InsertAsrHist(i, rec, sentence);
                }
                log.info("DoParseAsrResult({}).SetTaskFlag=2", rec.getRecorderid());
                TRecorder tRecorder = new TRecorder();
                tRecorder.setRecorderid(rec.getRecorderid());
                tRecorder.setTaskflag("2");
                tRecorderMapper.updateById(tRecorder);
                qmDataService.SetQmDataReady(rec.getCallid());
                //删除公网代理文件夹文件
                DeleteFileExample(rec.getFilename());
            }
        } catch (Exception e) {
            log.error("DoParseAsrResult.Err:{}", e.getMessage());
        }
    }

    public void DeleteFileExample(String filename) {
        // 指定要删除的文件路径
        Path path = Paths.get("/data/uploadrec/" + filename);

        try {
            // 删除文件（如果文件不存在，会抛出 NoSuchFileException）
            Files.delete(path);
            log.info("文件删除成功！");
        } catch (NoSuchFileException e) {
            log.error("DeleteFileExample.文件不存在:{}", path);
        } catch (IOException e) {
            log.error("DeleteFileExample.Err:{}", e.getMessage());
        }
    }

    private void DoParseAsrResul_N(String fileurl, TRecorder rec) {    //不使用
        String urlbody = asr_url + "tts/" + fileurl;
        try {
            log.info("DoParseAsrResult:{}", urlbody);
            //这样也可以取，但是对大数据量不太好处理
            //HttpResponse<String> response = Unirest.get(urlbody).asString();
            //log.info("DoAsrParse.Response:{}", response.getBody());
            //int status = response.getStatus();
            //if (status == 200) {
            URL url = new URL(urlbody);
            InputStream inputStream = url.openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            Integer index = 0;
            while ((line = reader.readLine()) != null) {
                //String ss = response.getBody();
                //String[] arr = ss.split("\n");
                //for (int k = 0; k < arr.length; k++) {
                //if (JPubUtils.IsEmpty(arr[k]) || arr[k].length() < 5)
                //    continue;
                log.info("DoParseAsrResult:{}", line);
                if (JPubUtils.IsNotEmpty(line) && line.length() > 5) {
                    JSONObject o = JSONObject.parseObject(line);
                    InsertAsrHist(index, rec, o);
                    index++;
                }
                //log.info("DoAsrParse:s={},e={},i={},text={}", s, e, i, text);
                //}
            }
            reader.close();
            inputStream.close();

            log.info("DoParseAsrResult({}).SetTaskFlag=2", rec.getRecorderid());
            TRecorder tRecorder = new TRecorder();
            tRecorder.setRecorderid(rec.getRecorderid());
            tRecorder.setTaskflag("2");
            tRecorderMapper.updateById(tRecorder);

            qmDataService.SetQmDataReady(rec.getCallid());
            //} else {
            //   log.warn("DoAsrParse.Fail:status={}", status);
            //}
        } catch (Exception e) {
            log.error("DoParseAsrResult.Err:{}", e.getMessage());
        }
    }

    private int InsertAsrHist(Integer index, TRecorder rec, JSONObject o) {
        try {
            Integer s = o.getInteger("BeginTime");
            Integer e = o.getInteger("EndTime");
            String text = o.getString("Text");
            if (JPubUtils.IsEmpty(text)) {
                return 0;
            }
            Integer i = -1;
            Object obj = o.get("ChannelId");
            if (obj != null) {
                i = o.getInteger("ChannelId");
            }
            AsrCallhist callhist = new AsrCallhist();
            String dn = rec.getChanneldn();

            String asrid = GetNextUID(dn, index);
            callhist.setAsrid(asrid);
            callhist.setDn(dn);
            callhist.setAgentid(rec.getAgentid());
            callhist.setCallid(rec.getCallid());
            callhist.setAni(rec.getTelno());
            callhist.setDnis(rec.getTeldnis());
            callhist.setAsrcontent(text);
            if (i < 0) {//表示是单通道录音
                callhist.setAsrstatus("channel");
            } else if (i == 1) {
                callhist.setAsrstatus("cust");
            } else {
                callhist.setAsrstatus("agent");
            }
            callhist.setCrdt(new Date());
            callhist.setAsrindex(index);
            callhist.setCalldir(rec.getCalltype());
            callhist.setStatus("1"); //0=实时，1=离线
            if (e > s) {
                BigDecimal span = new BigDecimal((e - s) / 1000.0);
                callhist.setSpan(span);
            } else {
                callhist.setSpan(new BigDecimal(0.0));
            }
            return asrCallhistMapper.insert(callhist);
        } catch (Exception e) {
            log.error("InsertAsrHist.Err:{}", e.getMessage());
            return -1;
        }
    }
}
